// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose: 	Implementation of IEventTarget wrt CXFormsElement.
//   $Id$


#include "stdafx.h"
#include "XFormsElement.h"
#include "DefaultUIEventHandlerMap.h"
#include "XFormsApp.h"

extern CXFormsApp theApp;

//Just Pass through to the owned eventTarget implementation
	STDMETHODIMP CXFormsElement::addEventListener(BSTR type, IEventListener * listener, BOOL useCapture)
	{
		HRESULT hr = E_NOTIMPL;
		CComPtr<IEventTarget> pTarget;
		getEventTargetImpl(&pTarget);
		if(pTarget)
		{
			hr = E_INVALIDARG;
			if(listener)
			{
				hr = pTarget->addEventListener(type, listener, useCapture);
			}
		}
		return hr;
	}

//Just Pass through to the owned eventTarget implementation
	STDMETHODIMP CXFormsElement::removeEventListener(BSTR type, IEventListener * listener, BOOL useCapture)
	{
	
		HRESULT hr = E_NOTIMPL;
		//Don't bother if the target has already been killed.
		if(m_pUnkInnerEventTarget)
		{
			CComPtr<IEventTarget> pTarget;
			getEventTargetImpl(&pTarget);
			if(pTarget)
			{
				hr = pTarget->removeEventListener(type, listener, useCapture);
			}
		}
		else
			hr = S_FALSE;
		return hr;
	}


	STDMETHODIMP CXFormsElement::dispatchEvent(IDOMEvent * evt,BOOL * pbCancelled)
	{
		HRESULT hr = S_FALSE;

		bool bDespatchEventEvents = false;
		CComQIPtr<IEventTarget> pContainer;
		if(evt && theApp.FormsManager().AreEventNotificationsEnabled() && m_pXForms) {
			CComBSTR sEventName;
			evt->get_type(&sEventName);
			if(sEventName != EVENT_EVENT_DISPATCHED && sEventName != EVENT_EVENT_COMPLETE) {
				CComPtr<IHTMLDocument2> pOwnerDocument;
				m_pXForms->GetOwnerDocument(&pOwnerDocument);
				CComQIPtr<IDispatch> pDispatch = pOwnerDocument;
				if(pDispatch) {
					DISPID dispid = 0;
					CComBSTR sPropertyName = L"EventTarget";
					pDispatch->GetIDsOfNames(IID_NULL, &sPropertyName, 1, LOCALE_SYSTEM_DEFAULT, &dispid);
					if(dispid != 0) {
						CComVariant vResult;
						DISPPARAMS params = {0,0,0,0};
						pDispatch->Invoke(dispid, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYGET, &params, &vResult, 0, 0);
						if(vResult.vt == VT_DISPATCH) {
							pContainer = vResult.pdispVal;
							if(pContainer)
								bDespatchEventEvents = true;
						}
					}
				}
			}
		}

		if(bDespatchEventEvents) {
			CComPtr<IEventEvent> pEventEvent;
			CreateEventEvent(&pEventEvent);
			if(pEventEvent) {
				CComBSTR sEventName = EVENT_EVENT_DISPATCHED;
				pEventEvent->initEventEvent(sEventName, VARIANT_FALSE, VARIANT_FALSE, evt);
				CComQIPtr<IDOMEvent> pDOMEvent = pEventEvent;
				BOOL bCancelled;
				pContainer->dispatchEvent(pDOMEvent, &bCancelled);
			}
		}

		//Pass up to run as MSHTMLEvent.
		__super::dispatchEvent(evt,pbCancelled);

		//Pass through to the owned formcontrol eventTarget
		CComPtr<IEventTarget> pTarget;
		getEventTargetImpl(&pTarget);
		if(pTarget)
			hr = pTarget->dispatchEvent(evt,pbCancelled);

		//run the default UI behaviour
		InvokeDefaultUIBehaviour(evt);

		if(bDespatchEventEvents) {
			CComPtr<IEventEvent> pEventEvent;
			CreateEventEvent(&pEventEvent);
			if(pEventEvent) {
				CComBSTR sEventName = EVENT_EVENT_COMPLETE;
				pEventEvent->initEventEvent(sEventName, VARIANT_FALSE, VARIANT_FALSE, evt);
				CComQIPtr<IDOMEvent> pDOMEvent = pEventEvent;
				BOOL bCancelled;
				pContainer->dispatchEvent(pDOMEvent, &bCancelled);
			}
		}

		return hr;
	}


	
	HRESULT CXFormsElement::InvokeDefaultUIBehaviour(IDOMEvent * pEvent)
	{
		HRESULT hr = E_INVALIDARG;
		if(pEvent)
		{
			//only execute if this is the target, not if bubbling has made it reach this point.
			CComPtr<IEventTarget> pTarget;
			pEvent->get_target(&pTarget);
			
			CComPtr<IEventTarget> pThisAsTarget;
			getEventTargetImpl(&pThisAsTarget);
			if(pThisAsTarget && pTarget)
			{
				IUnknown * pUnkTarget, * pUnkThisAsTarget;
				pThisAsTarget->QueryInterface(IID_IUnknown,reinterpret_cast<void**>(&pUnkThisAsTarget));
				pTarget->QueryInterface(IID_IUnknown,reinterpret_cast<void**>(&pUnkTarget));
				if(pUnkTarget == pUnkThisAsTarget)
				{
					CComBSTR sType;
					pEvent->get_type(&sType);
					//TODO:
					//Implement a map of function pointers to 
					//	event names.  Do the lookup, then call the function.
					HRESULT (*fn)(CXFormsElement*,IDOMEvent *) = 0;	
					CDefaultUIEventHandlerMap::GetHandlingFunction(sType,&fn);

					if(fn)
					{
						hr = fn(this,pEvent);
					}
					else
					{
						hr = E_NOTIMPL;
					}
				}
				else
				{
					hr = S_FALSE;
				}
				pUnkTarget->Release();
				pUnkThisAsTarget->Release();
			}
		}
		
		return hr;
	}